using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PACKETPARSERMAX20.CORE;

namespace PACKETPARSERMAX20.CORE.DEFINITIONS
{
    public class SMSG_MONSTER_MOVE_DEF : DefinitionBase
    {
     

        public override bool Process()
        {
            long current_position = base.Stream.Position;

            ProcessInternal(current_position);

            return Validate();
        }

        public override bool Process(uint pParentOpcode, uint opcode, long pPosition, long pSize)
        {
            base.SetCustomPositionAndSize(pPosition, pSize);
            ProcessInternal(pPosition);

            return ValidateMovementOpcode(pParentOpcode.ToString(), pPosition, pSize);
        }

        private void ProcessInternal(long pCurrentPosition)
        {
            base.Stream.Position = pCurrentPosition;

            MonsterMove monsterMove = new MonsterMove();

           // InitLog();


            monsterMove.guid = popGuid();
          //  if(LogIt) LogAppendLine("UInt64", "guid", monsterMove.guid, true);
            if (ClientBuild > 9767)
            {
                monsterMove.unkb1 = ReadByte();                                       // new in 3.1
              //  if(LogIt) LogAppendLine("byte", "unkb1", monsterMove.unkb1, "");
            }
            monsterMove.PositionInfo = ReadCoord3();
            //LogAppend(monsterMove.PositionInfo);
            monsterMove.mstime = ReadUInt32();
          //  if(LogIt) LogAppendLine("UInt32", "mstime", monsterMove.mstime);

            monsterMove.type = ReadByte();                                     // unknown
          //  if(LogIt) LogAppendLine("byte", "type", monsterMove.type);


            switch (monsterMove.type)
            {
                case 0:                                             // normal packet
                    break;
                case 1:                                             // stop packet (raw pos?)
                    UpdateObjectPosition(monsterMove.guid, monsterMove.PositionInfo.X, monsterMove.PositionInfo.Y, monsterMove.PositionInfo.Z, 0f, monsterMove.mstime);
                    break;
                case 2:                                             // facing spot, not used currently
                    monsterMove.facing1 = ReadFloat();
                    monsterMove.facing2 = ReadFloat();
                    monsterMove.facing3 = ReadFloat();

                  //  if(LogIt) LogAppendLine("float", "facing1", monsterMove.facing1);
                  //  if(LogIt) LogAppendLine("float", "facing2", monsterMove.facing2);
                  //  if(LogIt) LogAppendLine("float", "facing3", monsterMove.facing3);

                    break;
                case 3:                                             // not used currently
                    monsterMove.targetguid = ReadUInt64();                              // probably target guid (facing target?)
                  //  if(LogIt) LogAppendLine("UInt64", "targetguid", monsterMove.targetguid, false);

                    break;
                case 4:                                             // not used currently
                    monsterMove.facing0 = ReadFloat();                               // facing angle
                  //  if(LogIt) LogAppendLine("float", "facing0", monsterMove.facing0);

                    break;
            }

            if (monsterMove.type != 1)
            {
                monsterMove.flags = (MonsterMovementFlags)ReadUInt32();
              //  if(LogIt) LogAppendLine("uint32", "flags", (uint)monsterMove.flags, "MonsterMovementFlags", monsterMove.flags.DumpFlags());

                //if (((uint)monsterMove.flags) > 0)
                //{
                //    monsterMove.flags.DumpFlags();
                //}

                if ((monsterMove.flags & MonsterMovementFlags.MONSTER_MOVE_UNK1) != 0)
                {
                    UInt32 unk1 = ReadUInt32();
                    UInt32 unk2 = ReadUInt32();

                  //  if(LogIt) LogAppendLine("uint32", "unk1", unk1, "MONSTER_MOVE_UNK1=True");
                  //  if(LogIt) LogAppendLine("uint32", "unk2", unk1, "MONSTER_MOVE_UNK1=True");

                }

                if ((monsterMove.flags & MonsterMovementFlags.MONSTER_MOVE_UNK4) != 0)
                {
                    UInt32 unk1 = ReadUInt32();
                    byte unk2 = ReadByte();
                  //  if(LogIt) LogAppendLine("uint32", "unk3", unk1, "MONSTER_MOVE_UNK4=True");
                  //  if(LogIt) LogAppendLine("byte", "unk4", unk2, "MONSTER_MOVE_UNK4=True");

                }


                //MONSTER_MOVE_STRAFE_RIGHT 0x0008 = True
                //MONSTER_MOVE_TELEPORT 0x0100 = True

                if ((monsterMove.flags & MonsterMovementFlags.MONSTER_MOVE_STRAFE_RIGHT) != 0)
                {
                    float unk1 = ReadFloat();
                    float unk2 = ReadFloat();

                    //if (LogIt) LogAppendLine("float", "unk1", unk1, "MONSTER_MOVE_STRAFE_RIGHT=True");
                    //if (LogIt) LogAppendLine("float", "unk2", unk2, "MONSTER_MOVE_STRAFE_RIGHT=True");

                }

                monsterMove.moveTime = ReadUInt32();                               // Time in between points
              //  if(LogIt) LogAppendLine("UInt32", "moveTime", monsterMove.moveTime);
                monsterMove.count = ReadUInt32();
              //  if(LogIt) LogAppendLine("UInt32", "count", monsterMove.count);

                monsterMove.BasePositionInfo = ReadCoord3();
                //LogAppend(monsterMove.BasePositionInfo);

                if (((monsterMove.flags & (MonsterMovementFlags.MONSTER_MOVE_SPLINE | MonsterMovementFlags.MONSTER_MOVE_TELEPORT2)) != 0) && monsterMove.count > 1) //0x00002000
                {
                    monsterMove.SomeX = ReadFloat();
                  //  if(LogIt) LogAppendLine("float", "SomeX", monsterMove.SomeX, "before loop (MonsterMovementFlags.MONSTER_MOVE_SPLINE | MonsterMovementFlags.MONSTER_MOVE_TELEPORT2)) != 0) && monsterMove.count > 1 == TRUE");

                }

                float angle = Core.CalculateAngle(monsterMove.PositionInfo.X, monsterMove.PositionInfo.Y, monsterMove.BasePositionInfo.X, monsterMove.BasePositionInfo.Y);

                UpdateObjectPosition(monsterMove.guid, monsterMove.PositionInfo.X, monsterMove.PositionInfo.Y, monsterMove.PositionInfo.Z, angle, monsterMove.mstime);

                for (int i = 1; i < monsterMove.count; i++)                  // the single waypoint Point B
                {
                    MonsterMove.MonsterMoveNode node = new MonsterMove.MonsterMoveNode();
                    node.packedFloat = ReadInt32();
                  //  if(LogIt) LogAppendLine("Int32", "packedFloat", node.packedFloat);

                    node.node = new Coord3(monsterMove.BasePositionInfo.X + node.X, monsterMove.BasePositionInfo.Y + node.Y, monsterMove.BasePositionInfo.Z + node.Z);


                    if (((monsterMove.flags & (MonsterMovementFlags.MONSTER_MOVE_SPLINE | MonsterMovementFlags.MONSTER_MOVE_TELEPORT2)) != 0)) //0x00002000
                    {
                        node.coord = ReadFloat();
                      //  if(LogIt) LogAppendLine("float", "SomeZ", node.coord, "In loop (MonsterMovementFlags.MONSTER_MOVE_SPLINE | MonsterMovementFlags.MONSTER_MOVE_TELEPORT2)) != 0) == TRUE ");
                    }
                }

                List<float> FloatList = new List<float>();
                while (AvailableBytes > 0)
                {
                    float endfloat = ReadFloat();
                  //  if(LogIt) LogAppendLine("float", "endfloat", endfloat, "bunch of floats in end with no flags to specify why");
                    FloatList.Add(endfloat);
                }
            }


        }

        //////////////private void ProcessInternal(long pCurrentPosition)
        //////////////{
        //////////////    base.Stream.Position = pCurrentPosition;

        //////////////    ulong guid = popGuid();
        //////////////    if (ClientBuild > 9767)
        //////////////    {
        //////////////        byte unkb1 = ReadByte();                                       // new in 3.1
        //////////////    }
        //////////////    Coord3 Pos = ReadCoord3();
        //////////////    UInt32 mstime = ReadUInt32();
        //////////////    float O = 0f;
        //////////////    byte type = ReadByte();                                     // unknown
        //////////////    float facing1 = 0f;
        //////////////    float facing2 = 0f;
        //////////////    float facing3 = 0f;
        //////////////    UInt64 targetguid = 0;

        //////////////    switch (type)
        //////////////    {
        //////////////        case 0:                                             // normal packet
        //////////////            break;
        //////////////        case 1:                                             // stop packet (raw pos?)
        //////////////            UpdateObjectPosition(guid, Pos.X, Pos.Y, Pos.Z, 0f, mstime);
        //////////////            return;
        //////////////        case 2:                                             // facing spot, not used currently
        //////////////            facing1 = ReadFloat();
        //////////////            facing2 = ReadFloat();
        //////////////            facing3 = ReadFloat();
        //////////////            break;
        //////////////        case 3:                                             // not used currently
        //////////////            targetguid = ReadUInt64();                              // probably target guid (facing target?)
        //////////////            break;
        //////////////        case 4:                                             // not used currently
        //////////////            O = ReadFloat();                               // facing angle
        //////////////            break;
        //////////////    }

        //////////////    MonsterMovementFlags flags = (MonsterMovementFlags)ReadUInt32();

        //////////////    if (((uint)flags) > 0)
        //////////////    {
        //////////////        flags.DumpFlags();
        //////////////    }


        //////////////    UInt32 moveTime = 0;                               // Time in between points
        //////////////    UInt32 count = 0;

        //////////////    //if (ClientBuild < 9551)
        //////////////    //{
        //////////////    //    if ((flags & MonsterMovementFlags.MONSTER_MOVE_UNK5) > 0)
        //////////////    //    {
        //////////////    //        byte byte_1 = ReadByte();
        //////////////    //        UInt32 someMSTime = ReadUInt32();
        //////////////    //    }

        //////////////    //    moveTime = ReadUInt32();

        //////////////    //    if ((flags & MonsterMovementFlags.MONSTER_MOVE_STRAFE_RIGHT) > 0)
        //////////////    //    {
        //////////////    //        float float_1 = ReadSingle(); //speed?
        //////////////    //        UInt32 UInt32_1 = ReadUInt32(); //starttime speed up at this time?
        //////////////    //    }
        //////////////    //    count = ReadUInt32();

        //////////////    //}
        //////////////    //else
        //////////////    //{
        //////////////    if ((flags & MonsterMovementFlags.MONSTER_MOVE_UNK1) != 0)
        //////////////    {
        //////////////        UInt32 unk1 = ReadUInt32();
        //////////////        UInt32 unk2 = ReadUInt32();
        //////////////    }

        //////////////    moveTime = ReadUInt32();                               // Time in between points
        //////////////    count = ReadUInt32();
        //////////////    //}

        //////////////    // 1 single waypoint

        //////////////    Coord3 nodepos = ReadCoord3();
        //////////////    if (((flags & (MonsterMovementFlags.MONSTER_MOVE_SPLINE | MonsterMovementFlags.MONSTER_MOVE_TELEPORT2)) != 0) && count > 1) //0x00002000
        //////////////    {
        //////////////        float some_x = ReadFloat();
        //////////////    }


        //////////////    UpdateObjectPosition(guid, nodepos.X, nodepos.Y, nodepos.Z, 0f, mstime);


        //////////////    for (int i = 1; i < count; i++)                  // the single waypoint Point B
        //////////////    {
        //////////////        Int32 packedFloat = ReadInt32();
        //////////////        // unpacking
        //////////////        float offsetX = (float)((packedFloat & 0x7FF) << 21 >> 21) * 0.25f;
        //////////////        float offsetY = (float)((((packedFloat >> 11) & 0x7FF) << 21) >> 21) * 0.25f;
        //////////////        float offsetZ = (float)((packedFloat >> 22 << 22) >> 22) * 0.25f;

        //////////////        if (((flags & (MonsterMovementFlags.MONSTER_MOVE_SPLINE | MonsterMovementFlags.MONSTER_MOVE_TELEPORT2)) != 0) && count > 1) //0x00002000
        //////////////        {
        //////////////            float some_z = ReadFloat();
        //////////////        }

        //////////////        UpdateObjectPosition(guid, nodepos.X + offsetX, nodepos.Y + offsetY, nodepos.Z + offsetZ, O, mstime);

        //////////////    }

        //////////////    List<Coord3> PathList = new List<Coord3>();
        //////////////    while (AvailableBytes > 0)
        //////////////    {
        //////////////        Coord3 node = ReadCoord3();
        //////////////        PathList.Add(node);

        //////////////        UpdateObjectPosition(guid, node, O, mstime);
        //////////////    }
        //////////////}

        //public struct MonsterMove
        //{
        //    public ulong guid;


        //    public ulong transportGuid;
        //    public byte seatPos;


        //    public float x;
        //    public float y;
        //    public float z;
        //    public UInt32 ServerTime;
        //    public byte type;
        //    public UInt32 count;
        //    public UInt32 flags;

        //    public float targetPosX;
        //    public float targetPosY;
        //    public float targetPosZ;

        //    public ulong targetGuid;

        //    public float targetRot;

        //    public byte byte_1;
        //    public UInt32 someMSTime;

        //    public UInt32 moveTime;
        //    public float float_1;
        //    public UInt32 UInt32_1;

        //    public List<PathNode> PositionList;


        //    public Int32 packedFloat;

        //}

        //private void ProcessInternalA(long pCurrentPosition)
        //{
        //    base.Stream.Position = pCurrentPosition;

        //    //ulong guid = popGuid();
        //    //float x = ReadSingle();
        //    //float y = ReadSingle();
        //    //float z = ReadSingle();
        //    //float orientation = ReadSingle();

        //    //byte unk = ReadByte();
        //    //UInt32 flags = ReadUInt32();
        //    //UInt32 traveltime = ReadUInt32();
        //    //UInt32 pathSize = ReadUInt32();

        //    //for (UInt32 w = 0; w < pathSize; w++)
        //    //{
        //    //    float w_x = ReadSingle();
        //    //    float w_y = ReadSingle();
        //    //    float w_z = ReadSingle();
        //    //}

        //    //            0x0DD // SMSG_MONSTER_MOVE
        //    //0x2AE // SMSG_MONSTER_MOVE_TRANSPORT

        //    MonsterMove tMonsterMove = new MonsterMove();
        //    tMonsterMove.PositionList = new List<PathNode>();

        //    tMonsterMove.guid = popGuid();
        //    tMonsterMove.transportGuid = 0;
        //    tMonsterMove.seatPos = 0;

        //    tMonsterMove.x = ReadSingle();
        //    tMonsterMove.y = ReadSingle();
        //    tMonsterMove.z = ReadSingle();

        //    tMonsterMove.ServerTime = ReadUInt32(); // tickCount
        //    tMonsterMove.type = ReadByte();
        //    tMonsterMove.count = 0;
        //    tMonsterMove.flags = 0;

        //    switch (tMonsterMove.type)
        //    {
        //        case 1:
        //            break;
        //        case 2:
        //            tMonsterMove.targetPosX = ReadSingle();
        //            tMonsterMove.targetPosY = ReadSingle();
        //            tMonsterMove.targetPosZ = ReadSingle();
        //            break;
        //        case 3:
        //            tMonsterMove.targetGuid = ReadUInt64();
        //            break;
        //        case 4:
        //            tMonsterMove.targetRot = ReadSingle();
        //            break;
        //        default:
        //            break;
        //    }

        //    if (tMonsterMove.type == 1)
        //    {
        //        // do something, no data read
        //    }
        //    else
        //    {
        //        tMonsterMove.flags = ReadUInt32();  // movement flags
        //        if ((tMonsterMove.flags & 0x400000) > 0)
        //        {
        //            tMonsterMove.byte_1 = ReadByte();
        //            tMonsterMove.someMSTime = ReadUInt32();
        //        }
        //        tMonsterMove.moveTime = ReadUInt32();
        //        if ((tMonsterMove.flags & 0x8) > 0)
        //        {
        //            tMonsterMove.float_1 = ReadSingle(); //speed?
        //            tMonsterMove.UInt32_1 = ReadUInt32(); //starttime speed up at this time?
        //        }
        //        tMonsterMove.count = ReadUInt32();
        //    }

        //    if (tMonsterMove.type == 1)
        //    {
        //        // do something, no data read
        //    }
        //    else
        //    {
        //        if (!((tMonsterMove.flags & 0x80200) > 0))
        //        {

        //            float startX = 0;// ReadSingle();
        //            float startY = 0;// ReadSingle();
        //            float startZ = 0;// ReadSingle();
        //            tMonsterMove.PositionList.Add(new PathNode(startX = ReadSingle(), startY = ReadSingle(), startZ = ReadSingle()));

        //            if (tMonsterMove.count > 1)
        //            {
        //                if (tMonsterMove.count != 1) // wtf? blizz paranoic?
        //                {
        //                    for (int i = 0; i < tMonsterMove.count - 1; ++i)
        //                    {
        //                        tMonsterMove.packedFloat = ReadInt32();
        //                        // unpacking
        //                        float offsetX = (float)((tMonsterMove.packedFloat & 0x7FF) << 21 >> 21) * 0.25f;
        //                        float offsetY = (float)((((tMonsterMove.packedFloat >> 11) & 0x7FF) << 21) >> 21) * 0.25f;
        //                        float offsetZ = (float)((tMonsterMove.packedFloat >> 22 << 22) >> 22) * 0.25f;
        //                        float finalX = 0f;// startX + offsetX;
        //                        float finalY = 0f;//startX + offsetY;
        //                        float finalZ = 0f;//startX + offsetZ;

        //                        tMonsterMove.PositionList.Add(new PathNode(finalX = startX + offsetX, finalY = startX + offsetY, finalZ = startX + offsetZ));

        //                        // unpacked
        //                    }
        //                }
        //            }
        //        }
        //        else
        //        {
        //            float startX = 0;// ReadSingle();
        //            float startY = 0;// ReadSingle();
        //            float startZ = 0;// ReadSingle();

        //            tMonsterMove.PositionList.Add(new PathNode(startX = ReadSingle(), startY = ReadSingle(), startZ = ReadSingle()));

        //            if (tMonsterMove.count > 1)
        //            {
        //                for (int i = 0; i < tMonsterMove.count - 1; ++i)
        //                {
        //                    float finalX = ReadSingle();
        //                    float finalY = ReadSingle();
        //                    float finalZ = ReadSingle();
        //                    tMonsterMove.PositionList.Add(new PathNode(finalX, finalY, finalZ));

        //                }
        //            }
        //        }
        //    }

        //    tMonsterMove.PositionList.Add(new PathNode(tMonsterMove.x, tMonsterMove.y, tMonsterMove.z));

        //    foreach (PathNode tNode in tMonsterMove.PositionList)
        //    {


        //        Core.UpdateObjectPosition(tMonsterMove.guid, tNode.x, tNode.y, tNode.z, tMonsterMove.ServerTime, Opcode.ToString());
        //    }
        //}



    }
}
